﻿
#region Usings
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
#endregion

namespace FasterWPF
{
    public static class CommonInternalExt
    {      
        /// <summary>
        /// This should NOT be called directly. Use SortByText instead.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="sortOrder"></param>
        /// <param name="ChildLookupDict"></param>
        /// <param name="items"></param>
        /// <param name="controlType"></param>
        /// <returns></returns>
        internal static IEnumerable<string> PerformSortOfKeysLevelOne<T>(int row, int column, FasterWPF.CommonExt.SortOrder sortOrder, Dictionary<string, object> ChildLookupDict, IEnumerable<string> items, FasterWPF.CommonExt.SortControlType controlType)
        {
            string rowColumnStr = row + "_" + column;
            char[] underScore = new char[] { '_' };
            IEnumerable<string> itemsLeftOver = null;
            IEnumerable<string> itemsFinal = null;
            IEnumerable<KeyValuePair<string, object>> sourceLeftOver = null;

            if (controlType == FasterWPF.CommonExt.SortControlType.TextBlock)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? ((TextBlock)pair.Value) : (new TextBlock(new Run("")))).GetText() ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? ((TextBlock)pair.Value) : (new TextBlock(new Run("")))).GetText() descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else if (controlType == FasterWPF.CommonExt.SortControlType.TextBox)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? ((TextBox)pair.Value) : (new TextBox(){ Text=""})).Text ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? ((TextBox)pair.Value) : (new TextBox() { Text = "" })).Text descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else  //SortControlType.Label
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? ((Label)pair.Value) : (new Label() { Content = "" })).Content ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? ((Label)pair.Value) : (new Label() { Content = "" })).Content descending
                            select pair.Key.Split(underScore)[0];
                }
            }

            //add back any items that had been filtered out. Tack them on at the end
            sourceLeftOver = ChildLookupDict.Where(kvp => { return !items.Contains(kvp.Key.Split(underScore)[0]); });
            if (sourceLeftOver != null && sourceLeftOver.Count() > 0)
            {
                itemsLeftOver = sourceLeftOver.Select(kvp => { return kvp.Key.Split(underScore)[0]; }).Distinct();
                itemsFinal = items.Concat(itemsLeftOver);
                return itemsFinal;
            }

            return items;
        }

        /// <summary>
        /// This should NOT be called directly. Use SortByText instead.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="sortOrder"></param>
        /// <param name="ChildLookupDict"></param>
        /// <param name="items"></param>
        /// <param name="controlType"></param>
        /// <returns></returns>
        internal static IEnumerable<string> PerformSortOfKeysLevelOneDateTime<T>(int row, int column, FasterWPF.CommonExt.SortOrder sortOrder, Dictionary<string, object> ChildLookupDict, IEnumerable<string> items, FasterWPF.CommonExt.SortControlType controlType)
        {
            string rowColumnStr = row + "_" + column;
            char[] underScore = new char[] { '_' };
            IEnumerable<string> itemsLeftOver = null;
            IEnumerable<string> itemsFinal = null;
            IEnumerable<KeyValuePair<string, object>> sourceLeftOver = null;

            if (controlType == FasterWPF.CommonExt.SortControlType.TextBlock)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? DateTime.Parse(((TextBlock)pair.Value).GetText().ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? DateTime.Parse(((TextBlock)pair.Value).GetText().ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else if (controlType == FasterWPF.CommonExt.SortControlType.TextBox)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? DateTime.Parse(((TextBox)pair.Value).Text, new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? DateTime.Parse(((TextBox)pair.Value).Text, new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else  //SortControlType.Label
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? DateTime.Parse(((Label)pair.Value).Content.ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? DateTime.Parse(((Label)pair.Value).Content.ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : DateTime.Parse("1/1/1900", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }

            //add back any items that had been filtered out. Tack them on at the end
            sourceLeftOver = ChildLookupDict.Where(kvp => { return !items.Contains(kvp.Key.Split(underScore)[0]); });
            if (sourceLeftOver != null && sourceLeftOver.Count() > 0)
            {
                itemsLeftOver = sourceLeftOver.Select(kvp => { return kvp.Key.Split(underScore)[0]; }).Distinct();
                itemsFinal = items.Concat(itemsLeftOver);
                return itemsFinal;
            }

            return items;
        }

        /// <summary>
        /// This should NOT be called directly. Use SortByText instead.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="sortOrder"></param>
        /// <param name="ChildLookupDict"></param>
        /// <param name="items"></param>
        /// <param name="controlType"></param>
        /// <returns></returns>
        internal static IEnumerable<string> PerformSortOfKeysLevelOneDecimal<T>(int row, int column, FasterWPF.CommonExt.SortOrder sortOrder, Dictionary<string, object> ChildLookupDict, IEnumerable<string> items, FasterWPF.CommonExt.SortControlType controlType)
        {
            string rowColumnStr = row + "_" + column;
            char[] underScore = new char[] { '_' };
            IEnumerable<string> itemsLeftOver = null;
            IEnumerable<string> itemsFinal = null;
            IEnumerable<KeyValuePair<string, object>> sourceLeftOver = null;

            if (controlType == FasterWPF.CommonExt.SortControlType.TextBlock)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? Decimal.Parse(((TextBlock)pair.Value).GetText().ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? Decimal.Parse(((TextBlock)pair.Value).GetText().ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else if (controlType == FasterWPF.CommonExt.SortControlType.TextBox)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? Decimal.Parse(((TextBox)pair.Value).Text, new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? Decimal.Parse(((TextBox)pair.Value).Text, new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else  //SortControlType.Label
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? Decimal.Parse(((Label)pair.Value).Content.ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? Decimal.Parse(((Label)pair.Value).Content.ToString(), new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider) : Decimal.Parse("0.00", new CultureInfo(Thread.CurrentThread.CurrentCulture.ToString(), false) as IFormatProvider)) descending
                            select pair.Key.Split(underScore)[0];
                }
            }

            //add back any items that had been filtered out. Tack them on at the end
            sourceLeftOver = ChildLookupDict.Where(kvp => { return !items.Contains(kvp.Key.Split(underScore)[0]); });
            if (sourceLeftOver != null && sourceLeftOver.Count() > 0)
            {
                itemsLeftOver = sourceLeftOver.Select(kvp => { return kvp.Key.Split(underScore)[0]; }).Distinct();
                itemsFinal = items.Concat(itemsLeftOver);
                return itemsFinal;
            }

            return items;
        }

        /// <summary>
        /// This should NOT be called directly. Use SortByText instead.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="sortOrder"></param>
        /// <param name="ChildLookupDict"></param>
        /// <param name="items"></param>
        /// <param name="controlType"></param>
        /// <returns></returns>
        internal static IEnumerable<string> PerformSortOfKeysLevelOneInteger<T>(int row, int column, FasterWPF.CommonExt.SortOrder sortOrder, Dictionary<string, object> ChildLookupDict, IEnumerable<string> items, FasterWPF.CommonExt.SortControlType controlType)
        {
            string rowColumnStr = row + "_" + column;
            char[] underScore = new char[] { '_' };
            IEnumerable<string> itemsLeftOver = null;
            IEnumerable<string> itemsFinal = null;
            IEnumerable<KeyValuePair<string, object>> sourceLeftOver = null;

            if (controlType == FasterWPF.CommonExt.SortControlType.TextBlock)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? Int32.Parse(((TextBlock)pair.Value).GetText().ToString()) : Int32.Parse("0")) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBlock) ? Int32.Parse(((TextBlock)pair.Value).GetText().ToString()) : Int32.Parse("0")) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else if (controlType == FasterWPF.CommonExt.SortControlType.TextBox)
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? Int32.Parse(((TextBox)pair.Value).Text) : Int32.Parse("0")) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is TextBox) ? Int32.Parse(((TextBox)pair.Value).Text) : Int32.Parse("0")) descending
                            select pair.Key.Split(underScore)[0];
                }
            }
            else  //SortControlType.Label
            {
                if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc)
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? Int32.Parse(((Label)pair.Value).Content.ToString()) : Int32.Parse("0")) ascending
                            select pair.Key.Split(underScore)[0];
                }
                else
                {
                    items = from pair in ChildLookupDict
                            where (pair.Key.Split(underScore)[1] + "_" + pair.Key.Split(underScore)[2]) == (rowColumnStr)
                            orderby ((pair.Value is Label) ? Int32.Parse(((Label)pair.Value).Content.ToString()) : Int32.Parse("0")) descending
                            select pair.Key.Split(underScore)[0];
                }
            }

            //add back any items that had been filtered out. Tack them on at the end
            sourceLeftOver = ChildLookupDict.Where(kvp => { return !items.Contains(kvp.Key.Split(underScore)[0]); });
            if (sourceLeftOver != null && sourceLeftOver.Count() > 0)
            {
                itemsLeftOver = sourceLeftOver.Select(kvp => { return kvp.Key.Split(underScore)[0]; }).Distinct();
                itemsFinal = items.Concat(itemsLeftOver);
                return itemsFinal;
            }

            return items;
        }

        /// <summary>
        /// This should NOT be called directly. Use SortByText1AndThenBy2 instead.
        /// </summary>
        /// <param name="chain"></param>
        /// <param name="sortOrder"></param>
        /// <param name="sortOrder2"></param>
        /// <param name="sourceToSortOn"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        internal static IOrderedEnumerable<KeyValuePair<string, Tuple<object, object>>> PerformSortOfKeysLevelTwo(object chain, FasterWPF.CommonExt.SortOrder sortOrder, FasterWPF.CommonExt.SortOrder sortOrder2, Dictionary<string, Tuple<object, object>> sourceToSortOn, IOrderedEnumerable<KeyValuePair<string, Tuple<object, object>>> items, Type dataType1, Type dataType2)
        {
            //Sort
            if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc && sortOrder2 == FasterWPF.CommonExt.SortOrder.Asc)
            {
                items = from pair in sourceToSortOn
                        orderby Convert.ChangeType(pair.Value.Item1, dataType1) ascending, Convert.ChangeType(pair.Value.Item2, dataType2) ascending
                        select pair;
            }

            if (sortOrder == FasterWPF.CommonExt.SortOrder.Asc && sortOrder2 == FasterWPF.CommonExt.SortOrder.Desc)
            {
                items = from pair in sourceToSortOn
                        orderby Convert.ChangeType(pair.Value.Item1, dataType1) ascending, Convert.ChangeType(pair.Value.Item2, dataType2) descending
                        select pair;
            }

            if (sortOrder == FasterWPF.CommonExt.SortOrder.Desc && sortOrder2 == FasterWPF.CommonExt.SortOrder.Asc)
            {
                items = from pair in sourceToSortOn
                        orderby Convert.ChangeType(pair.Value.Item1, dataType1) descending, Convert.ChangeType(pair.Value.Item2, dataType2) ascending
                        select pair; 
            }

            if (sortOrder == FasterWPF.CommonExt.SortOrder.Desc && sortOrder2 == FasterWPF.CommonExt.SortOrder.Desc)
            {
                items = from pair in sourceToSortOn
                        orderby Convert.ChangeType(pair.Value.Item1, dataType1) descending, Convert.ChangeType(pair.Value.Item2, dataType2) descending
                        select pair;
            }

            return items;
        }

        /// <summary>
        /// This method assures that TextBlocks and Labels will always have an appropriate default value to sort on when sorting text by 1 and then by 2
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="row2"></param>
        /// <param name="column2"></param>
        /// <param name="sortControlType"></param>
        /// <param name="orderedKeys"></param>
        /// <param name="sourceToSortOn"></param>
        /// <param name="defaultValueForNull"></param>
        internal static void SetDefaultsForTextElementsAtRowCol<T>(object chain, int row, int column, int row2, int column2, CommonExt.SortControlType sortControlType, List<string> orderedKeys, Dictionary<string, Tuple<object, object>> sourceToSortOn, string defaultValueForNull, string defaultValueForNull2)
            where T : FrameworkElement
        {
            if (sortControlType == CommonExt.SortControlType.TextBlock)
            {
                //Filter to just the TextBlocks at that row-colum position
                foreach (string key in orderedKeys)
                {
                    object o1 = null;
                    TextBlock value = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row + "_" + column, out o1))
                    {
                        if (o1 is TextBlock && (o1 as TextBlock).GetText() != null && (o1 as TextBlock).GetText() != "")
                        {
                            value = (TextBlock)o1;
                        }
                        else
                        {
                            value = new TextBlock(new Run(defaultValueForNull));
                        }
                    }
                    else
                    {
                        value = new TextBlock(new Run(defaultValueForNull));
                    }

                    object o2 = null;
                    TextBlock value2 = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row2 + "_" + column2, out o2))
                    {
                        if (o2 is TextBlock && (o2 as TextBlock).GetText() != null && (o2 as TextBlock).GetText() != "")
                        {
                            value2 = (TextBlock)o2;
                        }
                        else
                        {
                            value2 = new TextBlock(new Run(defaultValueForNull2));
                        }
                    }
                    else
                    {
                        value2 = new TextBlock(new Run(defaultValueForNull2));
                    }

                    sourceToSortOn.Add(key, new Tuple<object, object>(value.GetText(), value2.GetText()));
                }
            }
            else if (sortControlType == CommonExt.SortControlType.TextBox)
            {
                //Filter to just the TextBlocks at that row-colum position
                foreach (string key in orderedKeys)
                {
                    object o1 = null;
                    TextBox value = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row + "_" + column, out o1))
                    {
                        if (o1 is TextBox && (o1 as TextBox).Text != null && (o1 as TextBox).Text != "")
                        {
                            value = (TextBox)o1;
                        }
                        else
                        {
                            value = new TextBox() { Text = defaultValueForNull };
                        }
                    }
                    else
                    {
                        value = new TextBox() { Text = defaultValueForNull };
                    }

                    object o2 = null;
                    TextBox value2 = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row2 + "_" + column2, out o2))
                    {
                        if (o2 is TextBox && (o2 as TextBox).Text != null && (o2 as TextBox).Text != "")
                        {
                            value2 = (TextBox)o2;
                        }
                        else
                        {
                            value2 = new TextBox() { Text = defaultValueForNull };
                        }
                    }
                    else
                    {
                        value2 = new TextBox() { Text = defaultValueForNull };
                    }

                    sourceToSortOn.Add(key, new Tuple<object, object>(value.Text.ToString(), value2.Text.ToString()));
                }
            }
            else //Label
            {
                //Filter to just the Labels at that row-colum position
                foreach (string key in orderedKeys)
                {
                    object o1 = null;
                    Label value = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row + "_" + column, out o1))
                    {
                        if (o1 is Label && (o1 as Label).Content!=null && (o1 as Label).Content!="")
                        {
                            value = (Label)o1;
                        }
                        else
                        {
                            value = new Label() { Content = defaultValueForNull };
                        }
                    }
                    else
                    {
                        value = new Label() { Content = defaultValueForNull };
                    }

                    object o2 = null;
                    Label value2 = null;

                    if (((Dictionary<string, object>)(((Dictionary<string, object>)((T)chain).Tag)["ChildLookup"])).TryGetValue(key + "_" + row2 + "_" + column2, out o2))
                    {
                        if (o2 is Label && (o2 as Label).Content!= null && (o2 as Label).Content!= "")
                        {
                            value2 = (Label)o2;
                        }
                        else
                        {
                            value2 = new Label() { Content = defaultValueForNull2 };
                        }
                    }
                    else
                    {
                        value2 = new Label() { Content = defaultValueForNull2 };
                    }

                    sourceToSortOn.Add(key, new Tuple<object, object>(value.Content.ToString(), value2.Content.ToString()));
                }
            }
        }
    }
}
